// PokerTable.m

#import "poker.h"
#import "IRCTask.h"

#define USER ([self findPlayerWithName:[[[NSApp delegate] userName]cString]])
@implementation PokerTable

// -----------------------------------------------------------------------------
// Override returning the nib file name of the document

- (NSString *)windowNibName {
    return @"PokerTable";
}

// -----------------------------------------------------------------------------
// Override

- (void)windowControllerDidLoadNib:(NSWindowController *) aController{
    [super windowControllerDidLoadNib:aController];
    [self newPokerTable];
}

// -----------------------------------------------------------------------------
// Override

- (NSData *)dataRepresentationOfType:(NSString *)aType {
    return nil;
}

// -----------------------------------------------------------------------------
// Override

- (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType {
    return YES;
}

- (IBAction)publicMessagePlayerAction:(id)sender { // send message to all
    [[Messager sharedInstance] showWindow:self];
}

- (IBAction)privateMessagePlayerAction:(id)sender { // click on a player to send message
    NSString *toWhom = [(id)[sender selectedTag] playerName];
    if (![[[NSApp delegate] userName] isEqualToString:toWhom]) {
        [[Messager messagerWithRecipient:toWhom] showWindow:self];
    }
}


- (IBAction)foldAction:(id)sender {
    [[IRCTask sharedIRCTask] fold];

}

- (IBAction)callAction:(id)sender {
    [[IRCTask sharedIRCTask] call];
}


- (IBAction)raisePotAction:(id)sender {
    [[IRCTask sharedIRCTask] pot];
}


- (IBAction)raiseHalfPotAction:(id)sender {
    [[IRCTask sharedIRCTask] halfPot];

}


- (IBAction)raiseMaximumAction:(id)sender {
    [[IRCTask sharedIRCTask] pushAllIn];

}


- (IBAction)raiseMinimumAction:(id)sender {
    [[IRCTask sharedIRCTask] minBet];

}


- (IBAction)raiseSpecifiedAmountAction:(id)sender {
    [[IRCTask sharedIRCTask] bet:[raiseSpecifiedField intValue]];

}

- (void)clearCell:(NSButtonCell *)cell {
    [cell setTag:0];
    [cell setBordered:NO];
    [cell setTransparent:YES];
    [cell setTitle:@""];
    [cell setEnabled:NO];
    [playersMatrix drawCell:cell];
}

- (void)populateCell:(NSButtonCell *)cell withPlayer:(Player *)player {
    [cell setTag:(int)player];
    [cell setBordered:YES];
    [cell setTransparent:NO];
    [cell setTitle:[player buttonTitle]];
    [cell setEnabled:YES];
    [playersMatrix drawCell:cell];
}


- (void)emptyPlayers {
    NSArray *cells = [playersMatrix cells];
    unsigned i = [cells count];
    while (i-- > 0) [self clearCell:[[playersMatrix cells] objectAtIndex:i]];
}


- (void)updateCardCells {
   unsigned i = 5;
   while (i--) {
       NSButtonCell *cell = [publicCardsMatrix cellAtRow:0 column:i];
       [cell setImage:[[[hand cards] objectAtIndex:i] image]];
//       [cell setImageDimsWhenDisabled:NO];
//       [cell setEnabled:NO];
   }
   [publicCardsMatrix display];
}

- (void)drawHoleCards {
    Player *user = USER;
    if (!user) {
        [[holeCardsMatrix cellAtRow:0 column:0] setImage:[NSImage imageNamed:@"0"]];
        [[holeCardsMatrix cellAtRow:0 column:1] setImage:[NSImage imageNamed:@"0"]];
    } else {
        [[holeCardsMatrix cellAtRow:0 column:0] setImage:[[[user holeHand]firstHoleCard] image]];
        [[holeCardsMatrix cellAtRow:0 column:1] setImage:[[[user holeHand]secondHoleCard] image]];
    }
/*
    [[holeCardsMatrix cellAtRow:0 column:0] setImageDimsWhenDisabled:NO];
    [[holeCardsMatrix cellAtRow:0 column:0] setEnabled:NO];
    [[holeCardsMatrix cellAtRow:0 column:1] setImageDimsWhenDisabled:NO];
    [[holeCardsMatrix cellAtRow:0 column:1] setEnabled:NO];
*/
    [holeCardsMatrix display];
}

- (void)newHand {
    buttonPlayer = nil;
    //user = nil;
    currentPlayer = nil;
    //[players makeObjectsPerformSelector:@selector(getNewHand)];
    [hand release];
    hand = [[HoldEmHighHand allocWithZone:[self zone]] init];
    [self updateCardCells];
    [self drawHoleCards];
    [self readyToBeginGame];
}

// hooks for cliff
- (void)newPokerTable {
       // clear out all players
       // turn over the main 5 cards and 2 hole cards
   players = [[NSMutableArray alloc] init];
   [self emptyPlayers];
 //  [self newHand];
}

- (void)userGotFirstHoleCard:(Card *)card secondCard:(Card *)secondCard {
    Player *user = USER;
    [[user holeHand] setSecondHoleCard:secondCard];
    [[user holeHand] setFirstHoleCard:card];
    [self drawHoleCards];
}


// pass in 0-4 for index
// and a 
- (void)publicCardNumber:(int)indexOfCard didShowCard:(Card *)card {
    NSButtonCell *cell = [publicCardsMatrix cellAtRow:0 column:indexOfCard];
    [hand setCard:card atIndex:indexOfCard];
    [cell setImage:[card image]];
    [publicCardsMatrix drawCellAtRow:0 column:indexOfCard];
}

typedef struct {
    int row;
    int col;
} RowCol;

static RowCol rowcols[24] = {
     { 0, 0 },
     { 0, 1 },
     { 0, 2 },
     { 0, 3 },
     { 0, 4 },
     { 0, 5 },
     { 0, 6 },
     { 1, 6 },
     { 2, 6 },
     { 3, 6 },
     { 4, 6 },
     { 5, 6 },
     { 6, 6 },
     { 6, 5 },
     { 6, 4 },
     { 6, 3 },  /* THIS IS WHERE I AM - 16th item */
     { 6, 2 },
     { 6, 1 },
     { 6, 0 },
     { 5, 0 },
     { 4, 0 },
     { 3, 0 },
     { 2, 0 },
     { 1, 0 }
};

#define ME_INDEX  15

- (void)readyToBeginGame {
    // what is the index of me?
    // how many players are there?
    // distribute them around by assigning them row's and col's
    int i, total = [players count];
    float skip = MAX(1,(int)(NUM_POSSIBLE_PLAYER_CELLS/(float)total));
    int indexOfMe = [players indexOfObject:USER];
    int currIndex;
    int baseIndex;
    currIndex = ME_INDEX - rint(indexOfMe * skip);
    if (indexOfMe == NSNotFound) currIndex = 0;

    if (currIndex < 0 ) currIndex += NUM_POSSIBLE_PLAYER_CELLS;
    baseIndex = currIndex;

    [self emptyPlayers];  // clears all cells
    for (i = 0; i < total; i++) {
         Player *player = [players objectAtIndex:i];
         [player setRow:rowcols[currIndex].row];
         [player setColumn:rowcols[currIndex].col];
         [self populateCell:[playersMatrix cellAtRow:[player row] column:[player column]]
		withPlayer:player];
	 currIndex += skip;
         if (currIndex >= NUM_POSSIBLE_PLAYER_CELLS) currIndex -= NUM_POSSIBLE_PLAYER_CELLS;
    }
    
}

- (void)updatePlayerTitle:(Player *)player {
    NSButtonCell *cell = [playersMatrix cellAtRow:[player row] column:[player column]];
    //[cell setEnabled:[player hasFolded]];
    [cell setTitle:[player buttonTitle]];
    [playersMatrix drawCellAtRow:[player row] column:[player column]];
}

- (void)player:(const char *)player hasCash:(int)amount {
    Player *play = [self findPlayerWithName:player];
    if (play) {
        if ([play isMe]) [myPot updatePotAmount:[play stackAmount]];

        [play setStackAmount:amount];
        [self updatePlayerTitle:play];
    }
}

- (void)beginAddingPlayers {
    buttonPlayer = nil;
    currentPlayer = nil;
    hasInitedPlayers = NO;
    [players removeAllObjects];
}


- (void)addPlayer:(const char *)player cash:(int)amount{
   // find a free cell
   // todo: good heuristic to assign players around table evenly
   Player *newPlayer;
   if ((newPlayer = [self findPlayerWithName:player]) == nil) {
    newPlayer = [[Player allocWithZone:[self zone]] initWithName:[NSString stringWithCString:player] pokerTable:self];
    [players addObject:newPlayer];
    }
   [newPlayer setStackAmount:amount];
}


- (void)deletePlayer:(const char *)player  {
    // find the cell of the player, remove it, redraw it
    // remove the player from list
    Player *remove = [self findPlayerWithName:player];
    if (remove) {
        [self clearCell:[playersMatrix cellWithTag:(int)remove]];
	[players removeObject:remove];
    }
}



- (Player *)findPlayerWithName:(const char *)playerName {
    if (!playerName) return nil;
    else {
        NSString *pName = [NSString stringWithCString:playerName];
        unsigned i = [players count];
        while (i-- > 0) {
        if ([[[players objectAtIndex:i] playerName] isEqualToString:pName])
                return [players objectAtIndex:i];
        }
        return nil;
    }
}


- (void)setButtonPlayer:(const char *)playerName {
    Player *oldButton = buttonPlayer;
    buttonPlayer = [self findPlayerWithName:playerName];
    if (oldButton)
	[self populateCell:[playersMatrix cellWithTag:(int)oldButton] withPlayer:oldButton];
    if (buttonPlayer)
        [self populateCell:[playersMatrix cellWithTag:(int)buttonPlayer] withPlayer:buttonPlayer];
    // PENDING draw focus ring
}


- (BOOL)isButtonPlayer:(Player *)player {
    if (!buttonPlayer) return NO;
    return [[player playerName] isEqualToString:[buttonPlayer playerName]];
}

// NSMatrix:
// NSButtonCell - _drawKeyboardFocusRingWithFrame:frame inView:controlView
/*
NSKeyboardFocusRingPrivate
_NSKeyboardFocusClipView
{?="highlightMode"b1"radioMode"b1"listMode"b1"allowEmptySel"b1"autoscroll"b1"selectionByRect"b1"drawsCellBackground"b1"drawsBackground"b1"autosizeCells"b1"drawingAncestor"b1"tabKeyTraversesCells"b1"tabKeyTraversesCellsExplicitlySet"b1"allowsIncrementalSearching"b1"currentlySelectingCell"b1"onlySetKeyCell"b1"changingSelectionWithKeyboard"b1"dontScroll"b1"refusesFirstResponder"b1"useSimpleTrackingMode"b1"checkForSimpleTrackingMode"b1"reservedMatrix"b12}
_changingSelectionWithKeyboard
_drawKeyboardFocusRingWithFrame:inView:
_setKeyboardFocusRingNeedsDisplay
_drawKeyboardFocusRingWithFrame:
*/

- (void)setPlayersTurn:(const char *)playerName {
    NSButtonCell *cell;
    NSRect r;

    currentPlayer = [self findPlayerWithName:playerName];
    cell = [playersMatrix cellWithTag:(int)currentPlayer];
    r = [playersMatrix cellFrameAtRow:[currentPlayer row] column:[currentPlayer column]];
    r = NSInsetRect(r, -4.0, -4.0);
    if (oldCell){
        [oldCell _setKeyboardFocusRingNeedsDisplay];
    [[[playersMatrix window] contentView] setNeedsDisplayInRect:[[[playersMatrix window] contentView]bounds]];
        [[playersMatrix window] display];

   }
    [cell _drawKeyboardFocusRingWithFrame:r inView:playersMatrix];
    oldCell = cell;
oldRect = [playersMatrix convertRect:oldRect toView:[[playersMatrix window] contentView]];
    oldRect = NSInsetRect(oldRect,-12.0,-12.0);
    if ([[currentPlayer playerName] isEqualToString:[[NSApp delegate] userName]])
        [[NSSound soundNamed:@"OpenShutter"] play];
}

- (void)setStatusString:(NSString *)message {
    [statusField setStringValue:message];
}

- (HoldEmHighHand *) hand
{
  return hand;
}

- (void)playerQuits:(const char *) playerName n_left:(int)nleft
{
   Player *player = [self findPlayerWithName:playerName];
    if (player) {
	[players removeObject:player];
        [self readyToBeginGame];
    }
}

- (void)tourneyStarted
{
 //   [self newHand];
    [self emptyPlayers];  // clears all cells

}

- (void)blindsAre:(int) small_blind and:(int) big_blind
{
    
}

- (void)player:(const char *)playerName toCall:(int)to_call
{
    [self setPlayersTurn:playerName];
    // state this PENDING
}

- (void)decrementAmount:(int)amount fromPlayer:(Player *)player {
    [player setStackAmount:[player stackAmount]- amount];
    [self updatePlayerTitle:player];
    if ([player  isMe]) [myPot updatePotAmount:[player stackAmount]];
}

- (void)incrementAmount:(int)amount toPlayer:(Player *)player {
    [player setStackAmount:[player stackAmount] + amount];
    [self updatePlayerTitle:player];
    if ([player  isMe]) [myPot updatePotAmount:[player stackAmount]];
}

- (void)player:(const char *)playerName blinds:(int)blind potNow:(int)pot allIn:(BOOL)allIn
{
    if (!hasInitedPlayers) {
         [self newHand];
         hasInitedPlayers = YES;
    }
    {
    Player *player = [self findPlayerWithName:playerName];
    [thePot updatePotAmount:pot];
    [self decrementAmount:blind fromPlayer:player];
    [myPot updatePotAmount:[USER stackAmount]];
    }
}

- (void) blindsWillDoubleIn:(int)blind_remaining units:(const char *)blind_remaining_units
{
// PENDING - place 10 second status string
}

- (void) beginHand:(int)hand_no n_players:(int)n_players
{
     [self newHand];
}

- (void)player:(const char *)playerName messages:(const char *)message {
    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithCString:message], @"Message",nil];
    [[NSNotificationCenter defaultCenter] postNotificationName:MessageReceivedNotification object:[NSString stringWithCString:playerName] userInfo:dict];
}


- (void) player:(const char *)playerName foldsLeaving:(int)n_players
{
    Player *player = [self findPlayerWithName:playerName];
    [player fold];
    [self updatePlayerTitle:player];
}

- (void) player:(const char *)playerName calls:(int)amount potNow:(int)pot allIn:(BOOL)allIn
{
    Player *player = [self findPlayerWithName:playerName];
    [thePot updatePotAmount:pot];
    [self decrementAmount:amount fromPlayer:player];
}

- (void) player:(const char *)playerName vacationedBy:(const char *)by_whom
{
    Player *player = [self findPlayerWithName:playerName];
    [player setOnVacation:YES];
    [self updatePlayerTitle:player];
}

- (void) playerChecks:(const char *)player
{
}

- (void) player:(const char *)playerName bets:(int)amount potNow:(int)pot allIn:(BOOL)allIn
{
    Player *player = [self findPlayerWithName:playerName];
    [thePot updatePotAmount:pot];
    [self decrementAmount:amount fromPlayer:player];
}

- (void) playerBackFromVacation:(const char *)playerName
{
    Player *player = [self findPlayerWithName:playerName];
    [player setOnVacation:NO];
    [self updatePlayerTitle:player];
}

- (void) player:(const char *)playerName wins:(int) amount withHand:(const char *)hand
{
    Player *player = [self findPlayerWithName:playerName];
    [thePot updatePotAmount:[thePot pot] - amount];
    [self incrementAmount:amount toPlayer:player];
}

- (void) aboutToShowHands
{
}

- (void) player:(const char *)playerName raises:(int)amount potNow:(int)pot allIn:(BOOL)allIn
{
    Player *player = [self findPlayerWithName:playerName];
    int oldPot = [thePot pot];
    [thePot updatePotAmount:pot];
    [self decrementAmount:pot - oldPot fromPlayer:player];
}

- (void) playerBusted:(const char *)playerName
{
    Player *player = [self findPlayerWithName:playerName];
    [self decrementAmount:[player stackAmount] fromPlayer:player];
}

- (void) playerQuit:(const char *)playerName
{
// stick up a tombstone PENDING
    [self deletePlayer:playerName];

}

@end
